package com.okex.open.api.ws;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.okex.open.api.bean.other.SpotOrderBook;
import com.okex.open.api.enums.CharsetEnum;
import com.okex.open.api.utils.DateUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dromara.northstar.common.model.core.Contract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;


/**
 * okx 私有频道 单例模式 交易 socket
 */
@Data
public class TradePrivateWebSocketClient {
    private static final Logger log = LoggerFactory.getLogger(TradePrivateWebSocketClient.class);

    private final String PRIVATE_SERVICE_URL = "wss://ws.okx.com:8443/ws/v5/private";
    private final String TEST_PRIVATE_SERVICE_URL = "wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999";

    private WebSocket webSocket = null;
    private final HashFunction crc32 = Hashing.crc32();
    private final Map<String, Optional<SpotOrderBook>> bookMap = new HashMap<>();
    public final Map<String, Contract> contractMap = new HashMap<>();
    private String gatewayId;
    private String accountType;
    private String apiKey;
    private String passphrase;
    private String secretKey;


    public TradePrivateWebSocketClient(String gatewayId, String apiKey, String secretKey, String passphrase, String accountType) {
        this.gatewayId = gatewayId;
        this.accountType = accountType;
        this.apiKey = apiKey;
        this.passphrase = passphrase;
        this.secretKey = secretKey;
    }

    public void connection(Consumer<String> messageCallback) {
        connection(accountType.equals("1") ? TEST_PRIVATE_SERVICE_URL : PRIVATE_SERVICE_URL, messageCallback);
        if (!ObjectUtil.isEmpty(apiKey)) {
            login(apiKey, passphrase, secretKey);
        }
    }

    public WebSocket connection(final String url, Consumer<String> messageCallback) {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(20, TimeUnit.SECONDS)
                .callTimeout(5, TimeUnit.SECONDS)
                .pingInterval(10, TimeUnit.SECONDS) // 发送心跳保活用的，不需要自己额外发送
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

        Request request = new Request.Builder()
                .url(url)
                .build();

        webSocket = client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(final WebSocket webSocket, final Response response) {
                log.info("WebSocket connected");
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                log.info("WebSocket closing: " + reason);
                webSocket.close(1000, "Long time no message was sent or received");
            }

            @Override
            public void onClosed(final WebSocket webSocket, final int code, final String reason) {
                log.info("WebSocket closed: " + reason);
            }

            @Override
            public void onFailure(final WebSocket webSocket, final Throwable t, final Response response) {
                log.error("WebSocket error: " + t.getMessage());
                messageCallback.accept("onFailure");
            }

            @Override
            public void onMessage(final WebSocket webSocket, final String text) {
                // Process received message
                messageCallback.accept(text);
            }
        });

        return webSocket;
    }

    // 获得sign
    private String sha256_HMAC(String message, String secret) {
        String hash = "";
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(CharsetEnum.UTF_8.charset()), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] bytes = sha256_HMAC.doFinal(message.getBytes(CharsetEnum.UTF_8.charset()));
            hash = Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            log.error("Error HmacSHA256: " + e.getMessage());
        }
        return hash;
    }

    // 登录
    public void login(String apiKey, String passPhrase, String secretKey) {
        String timestamp = System.currentTimeMillis() / 1000 + "";
        String message = timestamp + "GET" + "/users/self/verify";
        String sign = sha256_HMAC(message, secretKey);
        String str = "{\"op\":\"login\",\"args\":[{\"apiKey\":\"" + apiKey + "\",\"passphrase\":\"" + passPhrase + "\",\"timestamp\":\"" + timestamp + "\",\"sign\":\"" + sign + "\"}]}";
        sendMessage(str);
    }

    public void sendMessage(String message) {
        webSocket.send(message);
    }
}
